package server;

import java.io.BufferedReader;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.ShortMessage;

import mapper.OSC2MIDIBinding;
import mapper.OSC2MIDITranslation;
import midi.MidiManager;
import osc.OSCListener;
import osc.OSCMessage;
import parser.OSCMessageParser;

public class OSCServerThread extends Thread {

	private int inputPort = 57111;
	private int outputPort = 57112;

	private List<OSCListener> listeners = new ArrayList<OSCListener>();

	private boolean listening = true;

	protected DatagramSocket socket = null;
	protected BufferedReader in = null;

	public void addListener(OSCListener listener) {
		this.listeners.add(listener);
	}

	public OSCServerThread() throws IOException {
		this("OSCServerThread");
	}

	public OSCServerThread(String name) throws IOException {
		super(name);
		socket = new DatagramSocket(inputPort);
	}

	public void send(OSCMessage message, InetAddress address) {
		byte[] buffer = message.toByteArray();
		DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
		packet = new DatagramPacket(buffer, buffer.length, address, outputPort);
		try {
			socket.send(packet);
		} catch (IOException myIOException) {
			myIOException.printStackTrace();
		}
	}

	public void run() {

		OSCMessageParser myOSCparser = new OSCMessageParser();

		OSC2MIDITranslation translation = new OSC2MIDITranslation();

		// MOD Wheel
		OSC2MIDIBinding modBinding = new OSC2MIDIBinding(0, 176, 0, 1, 0, 127);

		translation.addBinding(modBinding);

		MidiManager manager = new MidiManager();
		manager.activate();

		while (listening) {
			try {
				byte[] buffer = new byte[256];

				DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
				socket.receive(packet);

				OSCMessage message = myOSCparser.parse(buffer);
				System.out.println(message);

				if (message.getTarget().compareTo("/1/fader2") == 0) {
					int output[] = modBinding.translate(message);
					ShortMessage midiMessage = new ShortMessage();
					try {
						midiMessage.setMessage(176, 1, 1, output[1]);
						manager.sendEvent(midiMessage, System.currentTimeMillis());
					} catch (InvalidMidiDataException myInvalidMidiDataException) {
						myInvalidMidiDataException.printStackTrace();
					}
				}

				InetAddress address = packet.getAddress();

				// System.out.println(address);

				for (OSCListener listener : listeners) {
					OSCMessage response = listener.messageReceived(message);
					if (response != null) {
						byte[] reponseBuffer = response.toByteArray();
						packet = new DatagramPacket(reponseBuffer, reponseBuffer.length, address, outputPort);
						socket.send(packet);
					}
				}

			} catch (IOException myIOException) {
				myIOException.printStackTrace();
				listening = false;
			}
		}
		socket.close();
	}
}
